using System;
using UnityEngine;
using Sirenix.OdinInspector;

/// <summary>
/// Attaching this script to an object will make it visibly follow another object, even if the two are using different cameras to draw them.
/// </summary>

public class UIFollowTarget : MonoBehaviour
{
	/// <summary>
	/// 3D target that this object will be positioned above.
	/// </summary>

	public Transform target;

	/// <summary>
	/// Game camera to use.
	/// </summary>

	public Camera gameCamera;

	/// <summary>
	/// UI camera to use.
	/// </summary>

	public Camera uiCamera;

	/// <summary>
	/// Whether the children will be disabled when this object is no longer visible.
	/// </summary>

	public bool disableIfInvisible = true;

	[LabelText("随相机高度增加进行缩小")]
	public bool scaleFollowCameraHeight = false;	// 默认是false，向前兼容
	[ShowIf("scaleFollowCameraHeight")]
	[LabelText("默认缩放时的标准相机高度")]
	public float standardCameraHeightOnScale = 25f;
	protected Vector3 _OriginScale = Vector3.one;

	[Obsolete("废弃，使用offsetUIValue")]
	public int offsetX
	{
		get => (int)_offsetUIValue.x;
		set => _offsetUIValue.x = value;
	}
	[Obsolete("废弃，使用offsetUIValue")]
	public int offsetY
	{
		get => (int)_offsetUIValue.y;
		set => _offsetUIValue.y = value;
	}

	protected Vector3 _offsetWorldValue = Vector3.zero;
	public Vector3 offsetWorldValue
	{
		get => _offsetWorldValue;
		set => _offsetWorldValue = value;
	}

	protected Vector3 _offsetUIValue = Vector3.zero;
	public  Vector3 offsetUIValue
	{
		get => _offsetUIValue;
		set => _offsetUIValue = value;
	}

	protected Transform mTrans;
	protected bool mIsVisible = false;

	public bool visible
	{
		get { return mIsVisible; }
	}

	protected static Camera _defaultUICamera;
	protected static Camera _defaultMainCamera;

	public static void ConfigureCamera(Camera uiCamera, Camera mainCamera = null)
	{
		_defaultUICamera = uiCamera;
		_defaultMainCamera = mainCamera;
	}

	protected bool mHasInit = false;

    public void ForceUpdate()
    {
        if(!mHasInit)
        {
            Awake();
            Start();
        }
        LateUpdate();
    }

    /// <summary>
    /// Cache the transform;
    /// </summary>
    protected void Awake()
    {
	    mTrans = transform;
    }

	/// <summary>
	/// Find both the UI camera and the game camera so they can be used for the position calculations
	/// </summary>
	protected void Start()
	{
		if (!mHasInit)
		{
			mHasInit = true;
			if (target != null)
			{
				if (gameCamera == null) 
				{
					if (!_defaultMainCamera)
					{
						_defaultMainCamera = Camera.main;
						if (_defaultMainCamera == null)
						{
							_defaultMainCamera = GameObject.FindWithTag("MainCamera")?.GetComponent<Camera>();
						}
					}
					gameCamera = _defaultMainCamera;
				}
				if (uiCamera == null) 
				{
					if (!_defaultUICamera)
					{
						var uicgo = GameObject.Find("UICamera");
						_defaultUICamera = uicgo ? uicgo.GetComponent<Camera>() : null;
					}
					uiCamera = _defaultUICamera;
				}
				SetVisible(false);
			}
			else
			{
				Debug.LogError("Expected to have 'target' set to a valid transform", this);
				enabled = false;
			}

			RectTransform rect = gameObject.GetComponent<RectTransform>();
			if (rect != null)
			{
				if (rect.anchorMin != _halfOne || rect.anchorMax != _halfOne)
				{
					Debug.LogError("This RectTransform has Anchors", this);
					enabled = false;
				}
			}

			_OriginScale = mTrans.localScale;
		}
	}
	
	protected Vector2 _halfOne = new Vector2(0.5f,0.5f);

	/// <summary>
	/// Enable or disable child objects.
	/// </summary>
	public void SetVisible (bool val)
	{
		mIsVisible = val;
#if UNITY_EDITOR
		if (mTrans.childCount > 1)
		{
			Debug.Log("实际子节点不能直接放在使用该组件的根节点下,需要增加一个二级节点！！");
		}
#endif
		for (int i = 0, imax = mTrans.childCount; i < imax; ++i)
		{
			mTrans.GetChild(i).gameObject.SetActive(val);
		}
	}

	/// <summary>
	/// Update the position of the HUD object every frame such that is position correctly over top of its real world object.
	/// </summary>
	protected void LateUpdate ()	
	{
		if (target == null)
		{
			Debug.LogError(this.gameObject + " " + this.mTrans.parent);
			this.enabled = false;
			return;
		}

		Vector3 pos = gameCamera.WorldToViewportPoint(target.position + _offsetWorldValue);

		// Determine the visibility and the target alpha
		bool isVisible = target.gameObject.activeInHierarchy && (gameCamera.orthographic || pos.z > 0f) && (!disableIfInvisible || (pos.x > 0f && pos.x < 1f && pos.y > 0f && pos.y < 1f));

		// Update the visibility flag
		if (mIsVisible != isVisible) SetVisible(isVisible);

		// If visible, update the position
		if (isVisible)
		{
			transform.position = uiCamera.ViewportToWorldPoint(pos);
			pos = mTrans.localPosition;
			pos                  = pos + offsetUIValue;
			pos.z                = 0f;
			mTrans.localPosition = pos;
			if (scaleFollowCameraHeight)
			{
				bool isOrthographic = gameCamera.orthographic;
				float curCameraScaleValue = isOrthographic ? gameCamera.orthographicSize : gameCamera.transform.localPosition.y;
				var curScale = standardCameraHeightOnScale / curCameraScaleValue;
				mTrans.localScale = _OriginScale * curScale;
			}
		}
		OnUpdate(isVisible);
	}

	/// <summary>
	/// Custom update function.
	/// </summary>

	protected virtual void OnUpdate (bool isVisible) { }
}
